package com.syt.mina.filter.codec.flex;

import java.io.DataInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.ASObject;
import flex.messaging.io.amf.Amf3Input;

public class AMF3Decoder extends CumulativeProtocolDecoder {
	private final AttributeKey POLICY = new AttributeKey(getClass(), "policy");
	private final String security = "<policy-file-request/>";
	private static final int MAX_BYTE_LENGTH = 2048;
	public AMF3Decoder() {
	}	

	
	private boolean isSecurityRequest(IoSession session, IoBuffer in){
		Boolean policy = (Boolean)session.getAttribute(POLICY);
		if(policy != null){
			return false;
		}
		String request = getRequest(in);
		boolean result = false;
		if(request != null){
			result = request.startsWith(security);
		}		 
		session.setAttribute(POLICY,new Boolean(result));
		return result;
	}
	
	private String getRequest(IoBuffer in){
		byte[] bytes = new byte[in.limit()];
		in.get(bytes);
		String request;
		try {
			request = new String(bytes,"UTF-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			request = null;
		}  
		return request;
	}

	private void sendSecurity(IoSession session){
		String security = 	"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "\n" +
							"	<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">" + "\n" +
							"	<cross-domain-policy>" + "\n" +
							"		<site-control permitted-cross-domain-policies=\"all\"/>" + "\n" +
							"		<allow-access-from domain=\"*.sungive.com\" to-ports=\"8899\" />" + "\n" +
							"		<allow-access-from domain=\"192.168.1.*\" to-ports=\"8899\" />" + "\n" +
							"	</cross-domain-policy>";
		session.write(security);		
	}
	
	protected boolean doDecode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		SerializationContext context = new SerializationContext();
		if(isSecurityRequest(session,in)){
			sendSecurity(session);
			in.free();
			return false;
		}else{
			in.position(0);
			int index = 0;
			boolean result = false;
			while(in.remaining() >= 4) {
				result = true;
				IoBuffer ib = in.getSlice(index, 4);
				int len = ib.getInt();
				if (len > MAX_BYTE_LENGTH) {
					in.free();
    				session.close(false);
    				result = false;
				}
				if (in.remaining() >= len + 4) {
					 byte bytes[] = new byte[len];
					 in.getInt();
					 in.get(bytes, 0, len);
					 index += len + 4;
					 IoBuffer tempIn = IoBuffer.wrap(bytes);
					 Amf3Input amf3in = new Amf3Input(context);
					 try {
						 InputStream inputStream = tempIn.asInputStream();
						 DataInputStream dataInputStream = new DataInputStream(inputStream);
						// InflaterInputStream inflater = new InflaterInputStream(dataInputStream);
						 amf3in.setInputStream(dataInputStream);
						 Object message = amf3in.readObject();	
						 try {
							 if(message instanceof ASObject){	
		        				ASObject object = (ASObject)message;	        				
		        				out.write(object);
		        			 }else{				
		        				in.free();
		        				session.close(false);
		        				result = false;
		        				break;
		        			}
						 }finally{
							 amf3in.close();
							 //inflater.close();
							 dataInputStream.close();
							 inputStream.close();
						 }
					 }catch (Exception e) {
						 e.printStackTrace();
					 }
				} else {
					result = false;
					break;
				}
			}
			return result;
		}
	}
	
	public static  int getMaxLength() {
		return MAX_BYTE_LENGTH;
	}
}
